<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Program Listing</title>
    <link rel="stylesheet" href="gettingStarted.css" type="text/css" />
    <meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
    <link rel="start" href="index.html" title="Getting Started with Replicated Berkeley DB Applications" />
    <link rel="up" href="writeforwarding.html" title="Chapter 5. Configuring for Write Forwarding" />
    <link rel="prev" href="writeforwarding.html" title="Chapter 5. Configuring for Write Forwarding" />
    <link rel="next" href="addfeatures.html" title="Chapter 6. Additional Features" />
  </head>
  <body>
    <div xmlns="" class="navheader">
      <div class="libver">
        <p>Library Version 12.1.6.2</p>
      </div>
      <table width="100%" summary="Navigation header">
        <tr>
          <th colspan="3" align="center">Program Listing</th>
        </tr>
        <tr>
          <td width="20%" align="left"><a accesskey="p" href="writeforwarding.html">Prev</a> </td>
          <th width="60%" align="center">Chapter 5. Configuring for Write Forwarding</th>
          <td width="20%" align="right"> <a accesskey="n" href="addfeatures.html">Next</a></td>
        </tr>
      </table>
      <hr />
    </div>
    <div class="sect1" lang="en" xml:lang="en">
      <div class="titlepage">
        <div>
          <div>
            <h2 class="title" style="clear: both"><a id="wrfor_programlisting"></a>Program Listing</h2>
          </div>
        </div>
      </div>
      <div class="toc">
        <dl>
          <dt>
            <span class="sect2">
              <a href="wrfor_programlisting.html#repwrforconfiginfo_cxx">
                            <span>Class: RepConfigInfo</span>
                            
                    </a>
            </span>
          </dt>
          <dt>
            <span class="sect2">
              <a href="wrfor_programlisting.html#repwrformgr_cxx">Class: excxx_repquote_gsg_RepMgrWrforGSG</a>
            </span>
          </dt>
          <dt>
            <span class="sect2">
              <a href="wrfor_programlisting.html#wrforusage_cxx">Function: usage()</a>
            </span>
          </dt>
          <dt>
            <span class="sect2">
              <a href="wrfor_programlisting.html#wrformain_cxx">Function: main()</a>
            </span>
          </dt>
          <dt>
            <span class="sect2">
              <a href="wrfor_programlisting.html#wrfor_init_cxx">Method: RepMgrWrforGSG::init()</a>
            </span>
          </dt>
          <dt>
            <span class="sect2">
              <a href="wrfor_programlisting.html#doloop_wrforcxx">Method: RepMgrWrforGSG::doloop()</a>
            </span>
          </dt>
          <dt>
            <span class="sect2">
              <a href="wrfor_programlisting.html#wrfor_printstocks_c">
                            
                            <span>Method: RepMgrWrforGSG::print_stocks()</span>
                                </a>
            </span>
          </dt>
        </dl>
      </div>
      <p> 
            Our example program builds from the simple transactional
            application you created in the <a class="xref" href="txnapp.html" title="Chapter 2. Transactional Application">Transactional Application</a> 
            chapter and configures write forwarding. The application is 
            network-aware, so you can specify things like host names and 
            ports from the command line. This program has additional error
            handling for replication errors. 
        </p>
      <p> 
            When using replication with write forwarding, there are several benefits for your application code: 
        </p>
      <div class="itemizedlist">
        <ul type="disc">
          <li>
            <p> 
                    You do not need to create an event handler to detect
                    changes of the master.
                </p>
          </li>
          <li>
            <p> 
                    You do not need to use app_data to track whether the
                    current site is master. 
                </p>
          </li>
          <li>
            <p>
                    You do not need to provide an error for put
                    operations on the client. 
                </p>
          </li>
        </ul>
      </div>
      <div class="sect2" lang="en" xml:lang="en">
        <div class="titlepage">
          <div>
            <div>
              <h3 class="title"><a id="repwrforconfiginfo_cxx"></a>
                            <span>Class: RepConfigInfo</span>
                            
                    </h3>
            </div>
          </div>
        </div>
        <p>
                            Before we begin, we present a 
                            class that we will use to maintain useful
                            information for us. 
                    </p>
        <p>
                            The class that we create is called
                            <code class="classname">RepConfigInfo</code>
                            .
                            
                    </p>
        <pre class="programlisting">#include &lt;db_cxx.h&gt;

class RepConfigInfo {
public:
    RepConfigInfo();
    virtual ~RepConfigInfo();

    void addOtherHost(char* host, int port);
    
public:
    u_int32_t start_policy;
    char* home;
    bool got_listen_address;
    REP_HOST_INFO this_host;
    int nrsites;
    // used to store a set of optional other hosts.
    REP_HOST_INFO *other_hosts;
};


RepConfigInfo::RepConfigInfo()
{
    start_policy = DB_REP_ELECTION;
    home = "TESTDIR";
    got_listen_address = false;
    nrsites = 0;
    other_hosts = NULL;
}

RepConfigInfo::~RepConfigInfo()
{
    // release any other_hosts structs.
    if (other_hosts != NULL) {
        REP_HOST_INFO *CurItem = other_hosts;
        while (CurItem-&gt;next != NULL) {
            REP_HOST_INFO *TmpItem = CurItem-&gt;next;
            free(CurItem);
            CurItem = TmpItem;
        }
        free(CurItem);
    }
    other_hosts = NULL;
}  </pre>
      </div>
      <div class="sect2" lang="en" xml:lang="en">
        <div class="titlepage">
          <div>
            <div>
              <h3 class="title"><a id="repwrformgr_cxx"></a>Class: excxx_repquote_gsg_RepMgrWrforGSG</h3>
            </div>
          </div>
        </div>
        <p>
                            Our example will 
                            instantiate a class,
                            <code class="classname">RepMgrWrforGSG</code>, that performs
                            all our work for us. Before we implement our
                            <code class="function">main()</code> function, we show
                            the <code class="classname">RepMgrWrforGSG</code> class
                            declaration.
                    </p>
        <p>
                            First, we provide some declarations and
                            definitions that are needed later in
                            our example. One is the size of our cache,
                            which we keep deliberately small for this example, and the other
                            is the name of our database. Also, you can define a sleep
                            time, which sets the time that a site waits before it retries
                            synchronizing with the master. We also provide a global variable that
                            is the name of our program; this is used for error reporting
                            later on. 
                    </p>
        <pre class="programlisting">#include &lt;iostream&gt;
#include &lt;errno.h&gt;
#include &lt;db_cxx.h&gt;
#include "RepWrforConfigInfo.h"


using std::cout;
using std::cin;
using std::cerr;
using std::endl;
using std::flush;

#define CACHESIZE   (10 * 1024 * 1024)
#define DATABASE    "quote.db"
#define SLEEPTIME 3

const char *progname = "excxx_repquote_gsg_wrfor";

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include &lt;windows.h&gt;
#include &lt;direct.h&gt;
#define    sleep(s)        Sleep(1000 * (s))

extern "C" {
  extern int getopt(int, char * const *, const char *);
  extern char *optarg;
}
#endif  </pre>
        <p>
        And then we define our <code class="classname">RepMgrWrforGSG</code> class:
</p>
        <pre class="programlisting">class RepMgrWrforGSG
{
public:
    // Constructor.
    RepMgrWrforGSG();
    // Initialization method. Creates and opens our environment handle.
    int init(RepConfigInfo* config);
    // The doloop is where all the work is performed.
    int doloop();
    // terminate() provides our shutdown code.
    int terminate();

private:
    // disable copy constructor.
    RepMgrWrforGSG(const RepMgrWrforGSG &amp;);
    void operator = (const RepMgrWrforGSG &amp;);

    // internal data members.
    RepConfigInfo   *app_config;
    DbEnv           dbenv;

    // private methods.
    // print_stocks() is used to display the contents of our database.
    static int print_stocks(Db *dbp);
};  </pre>
        <p>
            Note that we show the implementation of the various
            <code class="classname">RepMgrWrforGSG</code> methods later in this section.
    </p>
      </div>
      <div class="sect2" lang="en" xml:lang="en">
        <div class="titlepage">
          <div>
            <div>
              <h3 class="title"><a id="wrforusage_cxx"></a>Function: usage()</h3>
            </div>
          </div>
        </div>
        <p>
                            Our <code class="function">usage()</code> function
                            manages the following command line arguments:
                    </p>
        <pre class="programlisting">static void usage()
{
    cerr &lt;&lt; "usage: " &lt;&lt; progname &lt;&lt; endl
        &lt;&lt; "-h home -l|-L host:port [-r host:port]" &lt;&lt; endl;

    cerr 
        &lt;&lt; "\t -h home directory (required)" &lt;&lt; endl
        &lt;&lt; "\t -l host:port (required unless -L is specified;"
        &lt;&lt; "\t    l stands for local)" &lt;&lt; endl
        &lt;&lt; "\t -L host:port (optional, L means group creator)" &lt;&lt; endl
        &lt;&lt; "\t -r host:port (optional; r stands for remote; any "
        &lt;&lt; "number of these" &lt;&lt; endl
        &lt;&lt; "\t    may be specified)" &lt;&lt; endl;

    exit(EXIT_FAILURE);
}  </pre>
        <p> 
                where: 
            </p>
        <div class="itemizedlist">
          <ul type="disc">
            <li>
              <p>
                        <code class="literal">-h</code>
                    </p>
              <p> 
                        Identifies the environment home directory. You must
                        specify this option. 
                    </p>
            </li>
            <li>
              <p>
                        <code class="literal">-l</code>
                    </p>
              <p>
                        Identifies the host and port used by this site. You
                        must specify this option unless <code class="literal">-L</code> is
                        specified.
                    </p>
            </li>
            <li>
              <p>
                        <code class="literal">-L</code>
                    </p>
              <p> 
                        Identifies the local site as group creator. You must
                        specify this option unless <code class="literal">-l</code> is
                        specified.
                    </p>
            </li>
            <li>
              <p>
                        <code class="literal">-r</code>
                    </p>
              <p>
                        Optionally identifies another site participating in
                        this replication group.
                    </p>
            </li>
          </ul>
        </div>
      </div>
      <div class="sect2" lang="en" xml:lang="en">
        <div class="titlepage">
          <div>
            <div>
              <h3 class="title"><a id="wrformain_cxx"></a>Function: main()</h3>
            </div>
          </div>
        </div>
        <p>
                            Now we provide our <code class="function">main()</code>
                            function. This is a trivial function whose only
                            job is to collect command line information,
                            then instantiate a <code class="classname">RepMgrWrforGSG</code>
                            object, run it, then terminate it.
                    </p>
        <p>
                            We begin by declaring some useful variables. Of
                            these, note that we instantiate our
                            <code class="classname">RepConfigInfo</code>
                            object here. Recall that this is used to store
                            information useful to our code. 
                    </p>
        <pre class="programlisting">int main(int argc, char **argv)
{
    RepConfigInfo config;
    char ch, *last_colon, *portstr, *tmphost;
    int tmpport;
    int ret;  </pre>
        <p>
            Then we collect our command line information:
    </p>
        <pre class="programlisting">    // Extract the command line parameters
    while ((ch = getopt(argc, argv, "h:l:L:r:")) != EOF) {
        switch (ch) {
        case 'h':
            config.home = optarg;
            break;
        case 'L':
            config.this_host.creator = true; // FALLTHROUGH
        case 'l':
            config.this_host.host = optarg;
            /*
             * The final colon in host:port string is the
             * boundary between the host and the port portions
             * of the string.
             */
            if ((last_colon = strrchr(optarg, ':')) == NULL) {
                cerr &lt;&lt; "Bad local host specification." &lt;&lt; endl;
                usage();
            }
            /*
             * Separate the host and port portions of the 
             * string for further processing.
             */
            portstr = last_colon + 1;
            *last_colon = '\0';
            config.this_host.port = (unsigned short)atoi(portstr);
            config.got_listen_address = true;
            break;
        case 'r':
            tmphost = optarg;
            /*
             * The final colon in host:port string is the 
             * boundary between the host and the port portions
             * of the string.
             */
            if ((last_colon = strrchr(tmphost, ':')) == NULL) {
                cerr &lt;&lt; "Bad remote host specification." &lt;&lt; endl;
                usage();
            }
            /*
             * Separate the host and port portions of the 
             * string for further processing.
             */
            portstr = last_colon + 1;
            *last_colon = '\0';
            tmpport = (unsigned short)atoi(portstr);
            config.addOtherHost(tmphost, tmpport);
            break;
        case '?':
        default:
            usage();
        }
    }

    // Error check command line.
    if ((!config.got_listen_address) || config.home == NULL)
        usage();  </pre>
        <p>
        Now we instantiate and initialize our <code class="classname">RepMgrWrforGSG</code>
        class, which is what is responsible for doing all our real work.
        The <code class="methodname">RepMgrWrforGSG::init()</code> method creates and
        opens our environment handle.
</p>
        <pre class="programlisting">    RepMgrWrforGSG runner;
    try {
        if((ret = runner.init(&amp;config)) != 0)
            goto err;  </pre>
        <p>
            Then we call the <code class="methodname">RepMgrWrforGSG::doloop()</code>
            method, which is where the actual transactional work is
            performed for this application.
    </p>
        <pre class="programlisting">        if((ret = runner.doloop()) != 0)
            goto err;  </pre>
        <p>
                Finally, catch exceptions and terminate the program. Note, again,
                that in a traditional transactional application all databases would be closed here.
                In our replicated application, the database will usually be closed in the
                <code class="function">doloop()</code> function, but we also conditionally
                close the database here to handle some error cases.
        </p>
        <pre class="programlisting">    } catch (DbException dbe) {
        cerr &lt;&lt; "Caught an exception during initialization or"
            &lt;&lt; " processing: " &lt;&lt; dbe.what() &lt;&lt; endl;
    }
err:
    runner.terminate();
    return 0;
}  </pre>
      </div>
      <div class="sect2" lang="en" xml:lang="en">
        <div class="titlepage">
          <div>
            <div>
              <h3 class="title"><a id="wrfor_init_cxx"></a>Method: RepMgrWrforGSG::init()</h3>
            </div>
          </div>
        </div>
        <p>
                        The <code class="methodname">RepMgrWrforGSG::init()</code>
                        method is used to create and open our environment handle.
                </p>
        <p>
                        First, we show the class constructor
                        implementation, which is only used to initialize a
                        few variables:
                </p>
        <pre class="programlisting">RepMgrWrforGSG::RepMgrWrforGSG() : app_config(0), dbenv((u_int32_t)0)
{
}  </pre>
        <p>
                        We now provide the <code class="methodname">init()</code> method
                        implementation. You can now configure and start Replication Manager with
                        write forwarding. To configure write forwarding, use
                        <code class="function">rep_set_config</code> with the
                        <code class="literal">DB_REPMGR_CONF_FORWARD_WRITES</code> option:
                </p>
        <pre class="programlisting">int RepMgrWrforGSG::init(RepConfigInfo *config)
{
    int ret = 0;

    app_config = config;

    dbenv.set_errfile(stderr);
    dbenv.set_errpfx(progname);

    DbSite *dbsite;
    dbenv.repmgr_site(app_config-&gt;this_host.host,
        app_config-&gt;this_host.port, &amp;dbsite, 0);
    dbsite-&gt;set_config(DB_LOCAL_SITE, 1);
    if (app_config-&gt;this_host.creator)
        dbsite-&gt;set_config(DB_GROUP_CREATOR, 1);

    dbsite-&gt;close();

    int i = 1;
    for ( REP_HOST_INFO *cur = app_config-&gt;other_hosts;
        cur != NULL &amp;&amp; i &lt;= app_config-&gt;nrsites;
        cur = cur-&gt;next, i++) {

        dbenv.repmgr_site(cur-&gt;host, cur-&gt;port, &amp;dbsite, 0);
        dbsite-&gt;set_config(DB_BOOTSTRAP_HELPER, 1);

        dbsite-&gt;close();
    }

    // We can now open our environment, although we're not ready to
    // begin replicating.  However, we want to have a dbenv around
    // so that we can send it into any of our message handlers.
    dbenv.set_cachesize(0, CACHESIZE, 0);
    dbenv.set_flags(DB_TXN_NOSYNC, 1);

    try {
        dbenv.open(app_config-&gt;home, DB_CREATE | DB_RECOVER |
            DB_THREAD | DB_INIT_REP | DB_INIT_LOCK | DB_INIT_LOG | 
            DB_INIT_MPOOL | DB_INIT_TXN, 0);
    } catch(DbException dbe) {
        cerr &lt;&lt; "Caught an exception during DB environment open." &lt;&lt; endl
            &lt;&lt; "Ensure that the home directory is created prior"
            &lt;&lt; "to starting the application." &lt;&lt; endl;
        ret = ENOENT;
        goto err;
    }

    /* Configure Replication Manager write forwarding. */
    dbenv.rep_set_config(DB_REPMGR_CONF_FORWARD_WRITES, 1);

    if ((ret = dbenv.repmgr_start(3, app_config-&gt;start_policy)) != 0)
        goto err;

err:
    return ret;
}  </pre>
        <p>
        Finally, we present the <code class="methodname">RepMgrWrforGSG::terminate()</code>
        method here. All this does is close the environment handle.
</p>
        <pre class="programlisting">int RepMgrWrforGSG::terminate()
{
    try {
        dbenv.close(0);
    } catch (DbException dbe) {
        cerr &lt;&lt; "error closing environment: " &lt;&lt; dbe.what() &lt;&lt; endl;
    }
    return 0;
}  </pre>
      </div>
      <div class="sect2" lang="en" xml:lang="en">
        <div class="titlepage">
          <div>
            <div>
              <h3 class="title"><a id="doloop_wrforcxx"></a>Method: RepMgrWrforGSG::doloop()</h3>
            </div>
          </div>
        </div>
        <p>
                        Having written our <code class="function">main()</code>
                        function and support utility methods, we now implement 
                        our application's
                        primary data processing method. This
                        method provides a command prompt at which the
                        user can enter a stock ticker value and a price for
                        that value. This information is then entered to the
                        database.
                    </p>
        <p>
                            To display the database, simply enter
                            <code class="literal">return</code> at the prompt.
                    </p>
        <p>
                        To begin, we declare a database pointer,
                        several <code class="classname">Dbt</code> variables, and
                        the usual assortment of variables used for buffers
                        and return codes. We also initialize all of this.
                    </p>
        <pre class="programlisting">#define BUFSIZE 1024
int RepMgrWrforGSG::doloop()
{
    Dbt key, data;
    Db *dbp;
    char buf[BUFSIZE], *rbuf;
    int ret;

    dbp = 0;
    memset(&amp;key, 0, sizeof(key));
    memset(&amp;data, 0, sizeof(data));
    ret = 0;  </pre>
        <p>
                    Next, we begin the loop and we immediately open our
                    database if it has not already been opened.
                </p>
        <p> 
                    If <code class="literal">-L</code> is set, it specifies the need to
                    create the database for the initial group creator startup. The
                    database will be replicated to the other sites when they first
                    start up. The database will already exist on each site for
                    subsequent startups.
                </p>
        <p>
                    Note that there is some logic for a site to retry in case it
                    needs time to synchronize with the master using
                    <code class="literal">SLEEPTIME</code>.
                </p>
        <pre class="programlisting">    for (;;) {
        if (dbp == 0) {
            dbp = new Db(&amp;dbenv, 0);

            try {
                dbp-&gt;open(NULL, DATABASE, NULL, DB_BTREE,
                    app_config-&gt;
                           this_host.creator ? DB_CREATE | DB_AUTO_COMMIT :
                           DB_AUTO_COMMIT, 0);
            } catch(DbException dbe) {
                // It is expected that this condition will 
                // be triggered when client sites start up.  It can 
                // take a while for the master site to be found
                // and synced, and no DB will be available until then.
                if (dbe.get_errno() == ENOENT) {
                    cout &lt;&lt; "No stock db 
                    available yet - retrying." &lt;&lt; endl;
                    try {
                        dbp-&gt;close(0);
                    } catch (DbException dbe2) {
                        cout &lt;&lt; "Unexpected error closing after failed" &lt;&lt;
                            " open, message: " &lt;&lt; dbe2.what() &lt;&lt; endl;
                        dbp = NULL;
                        goto err;
                    }
                    dbp = NULL;
                    sleep(SLEEPTIME);
                    continue;
                } else {
                    dbenv.err(ret, "DB-&gt;open");
                    throw dbe;
                }
            }
        } </pre>
        <p>
            Now we implement our command prompt.
            If the user enters the keywords <code class="literal">exit</code>
            or <code class="literal">quit</code>, the loop is exited and the
            application ends. If the user enters nothing and instead simply
            presses <code class="literal">return</code>, the entire contents of the
            database is displayed. We use our
            <code class="function">print_stocks()</code> method to display the
            database. (That implementation is shown next in this chapter.)
        </p>
        <p>
            We also now check for a dead replication handle, which can occur
            in rare cases when a new master causes a previously committed 
            transaction to be rolled back. In such cases, all database handles
            must be closed and opened again.
        </p>
        <p> 
            Remember that very little error checking is performed on the
            data entered at this prompt. If the user fails to enter at least
            one space in the value string, a simple help message is printed
            and the prompt is returned to the user.
        </p>
        <pre class="programlisting">        cout &lt;&lt; "QUOTESERVER" ;
        cout &lt;&lt; "&gt; " &lt;&lt; flush;

        if (fgets(buf, sizeof(buf), stdin) == NULL)
            break;
        if (strtok(&amp;buf[0], " \t\n") == NULL) {
            switch ((ret = print_stocks(dbp))) {
            case 0:
                continue;
            case DB_REP_HANDLE_DEAD:
                (void)dbp-&gt;close(DB_NOSYNC);
                cout &lt;&lt; "closing db handle due to rep handle dead" &lt;&lt; endl;
                dbp = NULL;
                continue;
            default:
                dbp-&gt;err(ret, "Error traversing data");
                goto err;
            }
        }
        rbuf = strtok(NULL, " \t\n");
        if (rbuf == NULL || rbuf[0] == '\0') {
            if (strncmp(buf, "exit", 4) == 0 ||
                strncmp(buf, "quit", 4) == 0)
                break;
            dbenv.errx("Format: TICKER VALUE");
            continue;
        }  </pre>
        <p>
                Now we assign data to the <code class="classname">Dbt</code>s that
                we will use to write the new information to the database.
            </p>
        <pre class="programlisting">        key.set_data(buf);
        key.set_size((u_int32_t)strlen(buf));

        data.set_data(rbuf);
        data.set_size((u_int32_t)strlen(rbuf));  </pre>
        <p>
                Having done that, we can write the new information to the
                database. Here, the reason we do not need an explicit commit 
                on this put operation is that it uses the implicit NULL txnid, 
                so each one is automatically committed. Also, the application
                retries if a deadlock, timeout or permission error occurs. A forwarded
                put operation can return a timeout error if the operation takes
                too long and a permission error if there is currently
                no master.
            </p>
        <pre class="programlisting">        if ((ret = dbp-&gt;put(NULL, &amp;key, &amp;data, 0)) != 0)
        {
            dbp-&gt;err(ret, "DB-&gt;put");
            switch (ret) {
            case DB_REP_HANDLE_DEAD:
                /* Must close and reopen the handle, then can retry. */
                (void)dbp-&gt;close(0); 
                dbp = NULL;
                /* FALLTHROUGH */
            case DB_LOCK_DEADLOCK:
            case DB_TIMEOUT:
            case EACCES:
                dbenv.errx("Could not update data, retry operation");
            case DB_KEYEXIST:
                continue;
            default:
                dbp-&gt;err(ret, "Error updating data");
                goto err;
            }
        }
    }  </pre>
        <p>
            Finally, we close our database before returning from the
            method.
        </p>
        <pre class="programlisting">err:    if (dbp != NULL) {
        (void)dbp-&gt;close(DB_NOSYNC);
        cout &lt;&lt; "database closed" &lt;&lt; endl;
        }

    return (ret);
}  </pre>
      </div>
      <div class="sect2" lang="en" xml:lang="en">
        <div class="titlepage">
          <div>
            <div>
              <h3 class="title"><a id="wrfor_printstocks_c"></a>
                            
                            <span>Method: RepMgrWrforGSG::print_stocks()</span>
                                </h3>
            </div>
          </div>
        </div>
        <p>
               This function is unmodified from when we
               originally introduced it. For details on that function, see
               <a class="xref" href="simpleprogramlisting.html#printstocks_c" title="Method: SimpleTxn::print_stocks()">
                            
                            <span>Method: SimpleTxn::print_stocks()</span>
                            
                    </a>.
            </p>
      </div>
    </div>
    <div class="navfooter">
      <hr />
      <table width="100%" summary="Navigation footer">
        <tr>
          <td width="40%" align="left"><a accesskey="p" href="writeforwarding.html">Prev</a> </td>
          <td width="20%" align="center">
            <a accesskey="u" href="writeforwarding.html">Up</a>
          </td>
          <td width="40%" align="right"> <a accesskey="n" href="addfeatures.html">Next</a></td>
        </tr>
        <tr>
          <td width="40%" align="left" valign="top">Chapter 5. Configuring for Write Forwarding </td>
          <td width="20%" align="center">
            <a accesskey="h" href="index.html">Home</a>
          </td>
          <td width="40%" align="right" valign="top"> Chapter 6. Additional Features</td>
        </tr>
      </table>
    </div>
  </body>
</html>
